package service

import (
	"crypto/md5"
	"errors"
	"fmt"
	"gdmin/db"
	"gdmin/global"
	"gdmin/model"
	"gdmin/servlet"
	"gorm.io/gorm"
	"io"
	"math/rand"
)

type UserService struct{}

func (userService *UserService) CreateUser(req *servlet.CreateUserReq) (*model.User, error) {
	create, err := convertToCreate(req)
	err = checkLoginNameRequire(req.LoginName, -1)

	if err != nil {
		return nil, err
	}
	err = global.DB.Transaction(func(tx *gorm.DB) error {
		return tx.Save(&create).Error
	})
	if err != nil {
		return nil, err
	}
	return &create, err

}

func (userService *UserService) UpdateUser(req *servlet.UpdateUserReq) (*model.User, error) {
	err := validateToUpdate(req)
	if err != nil {
		return nil, err
	}

	var old model.User

	err = global.DB.First(&old, req.Id).Error

	if err != nil {
		return nil, err
	} else {

		err := checkLoginNameRequire(req.LoginName, req.Id)
		if err != nil {
			return nil, err
		}
		old.LoginName = req.LoginName
		old.Name = req.Name
		old.Email = req.Email
		old.Phone = req.Phone
		old.Sex = req.Sex
		if req.Password != "" {
			old.Password = genMd5Password(req.Password, old.Slat)
		}
		err = global.DB.Transaction(func(tx *gorm.DB) error {

			return tx.Save(&old).Error

		})
		if err != nil {
			return nil, err
		} else {

			return &old, nil

		}
	}

}

func (userService *UserService) QueryUser(req servlet.QueryUserReq) *servlet.Pagination {
	var d []*model.User

	query := global.DB.Model(&d)
	if req.Name != "" {
		query.Where("name like ? ", "%"+req.Name+"%")
	}
	if req.Phone != "" {
		query.Where("phone like ? ", "%"+req.Phone+"%")
	}
	if req.LoginName != "" {
		query.Where("login_name like ? ", "%"+req.LoginName+"%")
	}
	if req.Sex != "" {
		query.Where("sex = ? ", req.Sex)
	}

	return db.CommonPage(&req.Pagination, &d, query)

}

func (userService *UserService) List() []servlet.UserResp {
	var d []servlet.UserResp
	global.DB.Find(&d)
	return d

}

func (userService *UserService) QueryUserById(id string) *servlet.UserResp {
	var res servlet.UserResp
	global.DB.Model(&model.User{}).Where("id = ?", id).Find(&res)

	res.Roles = findRole(res.Id)
	userService.handlerUserInfo(&res)
	return &res

}

func (userService *UserService) handlerUserInfo(s *servlet.UserResp) {
	var d []model.DeptBindUser
	global.DB.Model(&model.DeptBindUser{}).Where("user_id =?", s.Id).Find(&d)
	if len(d) > 0 {

		var deptIds []int
		for _, item := range d {
			if item.IsMain {
				s.MainDeptId = item.DeptId
			}
			deptIds = append(deptIds, item.DeptId)
		}
		s.DeptIds = deptIds

	}
}

func findRole(userId int) []model.Role {
	var ids []int
	global.DB.Model(&model.RoleBindUser{}).Where("user_id =?", userId).Select("role_id").Find(&ids)
	var role []model.Role
	global.DB.Model(&model.Role{}).Where("id in ?", ids).Find(&role)
	return role
}

func (userService *UserService) Login(req *servlet.LoginReq) (*model.User, error) {
	user := model.User{}
	err := global.DB.Model(&user).Where("login_name = ?", req.LoginName).Find(&user).Error
	if err != nil {
		return nil, err

	}
	password := genMd5Password(req.Password, user.Slat)
	if password == user.Password {
		var resp servlet.LoginResp
		resp.Token = genJwtToken(user.Id)

		return &user, nil
	}
	return nil, errors.New("密码错误")
}

func (userService *UserService) DeleteById(param string) error {
	if param == "1" {
		return nil
	}
	return global.DB.Transaction(func(tx *gorm.DB) error {
		return tx.Delete(&model.User{}, param).Error
	})
}

func genJwtToken(id int) string {
	return ""

}

func checkLoginNameRequire(loginName string, id int) error {
	user := model.User{}
	err := global.DB.Where("login_name =?", loginName).Find(&user).Error
	if err == nil {
		if user.Id == 0 {
			return nil
		}
		if user.Id != id {
			return errors.New("登录名已存在")
		}
	} else {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil
		}
	}

	return err
}

func convertToCreate(req *servlet.CreateUserReq) (model.User, error) {
	err := validateToCreate(req)
	if err != nil {
		panic(err)
	}

	var dbUser model.User

	dbUser.Name = req.Name
	dbUser.LoginName = req.LoginName
	dbUser.Email = req.Email
	dbUser.Sex = req.Sex
	dbUser.Phone = req.Phone
	lower := randStr(10)
	dbUser.Slat = lower

	dbUser.Password = genMd5Password(req.Password, lower)
	return dbUser, err

}

var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")

func randStr(n int) string {
	b := make([]rune, n)
	for i := range b {
		b[i] = letters[rand.Intn(len(letters))]
	}
	return string(b)
}

func genMd5Password(password string, salt string) string {
	h := md5.New()
	_, _ = io.WriteString(h, password+salt)
	return fmt.Sprintf("%x", h.Sum(nil))
}

func validateToCreate(req *servlet.CreateUserReq) error {

	return nil

}

func validateToUpdate(req *servlet.UpdateUserReq) error {
	if req.Id > 0 {
		return nil
	}
	return errors.New("用户id必填")

}
